/*
This file is part of Docking@Home.
http://docking.gcl.cis.udel.edu
Copyright (C) 2009 University of Delaware

Docking@Home is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Docking@Home is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Docking@Home.  If not, see <http://www.gnu.org/licenses/>.
*/
/*
	Filename: LowLevelTab.cpp
	Description: A tab in our gui that will control and display any of the low
		level details of the protein and ligand.
	Revision History: 
		Created - 01/02/08
	Author: Robert Keller
*/

#include "LowLevelTab.h"

#include "../Button/TextButton.h"
#include "../Button/ImageButton.h"
#include "../BioModels/Protein.h"
#include "../BioModels/Ligand.h"
#include "../ActionIDs.h"

#include "parse.h"
#include "gutil.h"
#include "boinc_gl.h"
#include "graphics_api.h"
#include "txf_util.h"

// ------------------------------------------------------------
// Constructor / Destructor
// ------------------------------------------------------------

LowLevelTab::LowLevelTab ()
	: WAIT_TIME(2),
	  DEFAULT_VIEW_CHANGING_SIZE(50.0f)
{
	setName("");
}// LowLevelTab

LowLevelTab::LowLevelTab (const char n[TAB_MAX_NAME_LENGTH])
	: WAIT_TIME(2),
	  DEFAULT_VIEW_CHANGING_SIZE(50.0f)
{
	setName(n);
}// LowLevelTab

LowLevelTab::~LowLevelTab ()
{
	unsigned int i;

	for (i = 0; i < models.size(); i++)
		delete models[i];

	models.clear();

	for (i = 0; i < bioTypeButtons.size(); i++)
		delete bioTypeButtons[i];

	bioTypeButtons.clear();

	for (i = 0; i < viewChangingButtons.size(); i++)
		delete viewChangingButtons[i];

	viewChangingButtons.clear();

	delete resources;

}// ~LowLevelTab

// ------------------------------------------------------------
// Initialization Functions
// ------------------------------------------------------------

void LowLevelTab::init (TabWindow * tabWindow, float ls)
{
	char path[256];

	setTabWindow(tabWindow);
	
	//we'll start these early so it forces to check for models and resources
	models_startTime=0;
	resourceStartTime=0;

	// Text Properties 
	setLineSpacing(ls);

	textXScale = 0.0f;
	textYScale = 0.0f;

	textStandardXScale = 0.80f;
	textStandardYScale = -0.80f;

	// Ligand Text Properties
	ligandTextScaleX = 0.75f;
	ligandTextScaleY = -0.75f;

	ligandPaddingX = 12.0f;
	ligandPaddingY = 8.0f;

	// Create the buttons
	float middleRightX = (float)tabWindow->getMiddleX() 
		+ (tabWindow->getBottomRightX() 
		- tabWindow->getMiddleX()) / 2.0f;

	// Zoom in button
	ImageButton * imageButton = 
		new ImageButton("Zoom In", 
			middleRightX - DEFAULT_VIEW_CHANGING_SIZE,
			(float)tabWindow->getBottomRightY() 
				- DEFAULT_VIEW_CHANGING_SIZE - 1.0f,
			DEFAULT_VIEW_CHANGING_SIZE,
			DEFAULT_VIEW_CHANGING_SIZE);

	boinc_resolve_filename("plus.jpg", path, sizeof(path));
	imageButton->loadImage(path);

	imageButton->setUnselectedColor(glHelper->WHITE);
	imageButton->setSelectedColor(glHelper->YELLOW);
	imageButton->setHoverColor(glHelper->CYAN);

	imageButton->setActionID(ACT_ZOOM_IN);

	// Add image 

	viewChangingButtons.push_back(imageButton);

	// Zoom out
	imageButton = 
		new ImageButton("Zoom Out", 
			middleRightX,
			(float)tabWindow->getBottomRightY()
				- DEFAULT_VIEW_CHANGING_SIZE - 1.0f,
			DEFAULT_VIEW_CHANGING_SIZE,
			DEFAULT_VIEW_CHANGING_SIZE);

	boinc_resolve_filename("minus.jpg", path, sizeof(path));
	imageButton->loadImage(path);

	imageButton->setUnselectedColor(glHelper->WHITE);
	imageButton->setSelectedColor(glHelper->YELLOW);
	imageButton->setHoverColor(glHelper->CYAN);

	imageButton->setActionID(ACT_ZOOM_OUT);

	// Add image

	viewChangingButtons.push_back(imageButton);

	// Rotate Left
	imageButton = 
		new ImageButton("Rotate Left", 
			middleRightX - 2.0f * DEFAULT_VIEW_CHANGING_SIZE,
			(float)tabWindow->getBottomRightY()
				- DEFAULT_VIEW_CHANGING_SIZE - 1.0f,
			DEFAULT_VIEW_CHANGING_SIZE,
			DEFAULT_VIEW_CHANGING_SIZE);

	boinc_resolve_filename("rotate_left.jpg", path, sizeof(path));
	imageButton->loadImage(path);

	imageButton->setUnselectedColor(glHelper->WHITE);
	imageButton->setSelectedColor(glHelper->YELLOW);
	imageButton->setHoverColor(glHelper->CYAN);

	imageButton->setActionID(ACT_ROTATE_LEFT);

	// Add image

	viewChangingButtons.push_back(imageButton);

	// Rotate Right
	imageButton = 
		new ImageButton("Rotate Right", 
			middleRightX + DEFAULT_VIEW_CHANGING_SIZE,
			(float)tabWindow->getBottomRightY()
				- DEFAULT_VIEW_CHANGING_SIZE - 1.0f,
			DEFAULT_VIEW_CHANGING_SIZE,
			DEFAULT_VIEW_CHANGING_SIZE);

	boinc_resolve_filename("rotate_right.jpg", path, sizeof(path));
	imageButton->loadImage(path);

	imageButton->setUnselectedColor(glHelper->WHITE);
	imageButton->setSelectedColor(glHelper->YELLOW);
	imageButton->setHoverColor(glHelper->CYAN);

	imageButton->setActionID(ACT_ROTATE_RIGHT);

	// Add image

	viewChangingButtons.push_back(imageButton);

	// Protein Button

	TextButton * textButton = 
		new TextButton ("Protein", 
			(float)tabWindow->getTopLeftX(), 
			(float)tabWindow->getTopLeftY() + lineSpacing,
			1.0f, 1.0f, 1.0f, .1f);

	textButton->setUnselectedColor(glHelper->WHITE);
	textButton->setSelectedColor(glHelper->YELLOW);
	textButton->setHoverColor(glHelper->CYAN);

	textButton->setHoldSelection(true);
	textButton->select();

	textButton->setActionID(ACT_DISPLAY_PROTEIN);

	// Add Text Button

	bioTypeButtons.push_back(textButton);

	// Ligand Button

	textButton = 
		new TextButton ("Ligand", 
			(float)tabWindow->getTopLeftX(), 
			(float)tabWindow->getTopLeftY() + 3 * lineSpacing,
			1.0f, 1.0f, 1.0f, .1f);

	textButton->setUnselectedColor(glHelper->WHITE);
	textButton->setSelectedColor(glHelper->YELLOW);
	textButton->setHoverColor(glHelper->CYAN);

	textButton->setHoldSelection(true);

	textButton->setActionID(ACT_DISPLAY_LIGAND);

	// Add Text Button

	bioTypeButtons.push_back(textButton);

	// Complex Button

	textButton = 
		new TextButton ("Complex", 
			(float)tabWindow->getTopLeftX(), 
			(float)tabWindow->getTopLeftY() + 5 * lineSpacing,
			1.0f, 1.0f, 1.0f, .1f);

	textButton->setUnselectedColor(glHelper->WHITE);
	textButton->setSelectedColor(glHelper->YELLOW);
	textButton->setHoverColor(glHelper->CYAN);

	textButton->setHoldSelection(true);

	textButton->setActionID(ACT_DISPLAY_COMPLEX);

	// Add Text Button

	bioTypeButtons.push_back(textButton);

	// Resource Button

	textButton = 
		new TextButton ("Resources",
			(float)tabWindow->getTopLeftX(), 
			(float)tabWindow->getTopLeftY() + 7 * lineSpacing,
			1.0f, 1.0f, 1.0f, .1f);

	textButton->setUnselectedColor(glHelper->WHITE);
	textButton->setSelectedColor(glHelper->YELLOW);
	textButton->setHoverColor(glHelper->CYAN);

	textButton->setHoldSelection(true);

	textButton->setActionID(ACT_DISPLAY_RESOURCES);

	// Add Button

	bioTypeButtons.push_back(textButton);

	// Load Models

	currentModel = 0;
	
	currentView.viewType = MODELS;
	currentView.bShowViewChangingControls = true;

	Protein * protein = new Protein("receptor.pdb", 
		"receptor.psf");

	Ligand * ligand = new Ligand("screenenergy.pdb", 
		"screenenergy.psf");
	bMinEner = true;

	models.push_back (protein);
	models.push_back (ligand);

	resources = new Resources(20.0f, 50.0f, 30.0f);

	resources->setTextColor(glHelper->WHITE);
	resources->setCylinderFullColor(glHelper->CYAN);
	resources->setCylinderEmptyColor(glHelper->GRAY);

	setTextColor(glHelper->WHITE);

	// bodyModel.loadModel("box.obj");

}// init

void LowLevelTab::initResourceInfo(
	const char uname[TAB_MAX_NAME_LENGTH],
	const char gname[TAB_MAX_NAME_LENGTH])
{
	resources->setUserName(uname);
	resources->setGroupName(gname);

}// initResourceInfo

// ------------------------------------------------------------
// Required Tab Functions 
// ------------------------------------------------------------

void LowLevelTab::resizeScales (bool bFullscreen)
{
	unsigned int i;

	for (i = 0; i < bioTypeButtons.size(); i++)
	{
		bioTypeButtons[i]->resizeSameLeft(
			tabWindow->getWidthFactor(),
			tabWindow->getHeightFactor(),
			tabWindow->STANDARD_WIDTH,
			tabWindow->getWindowWidth());
	}// for

	for (i = 0; i < viewChangingButtons.size(); i++)
	{
		viewChangingButtons[i]->resizeSameBottom(
			tabWindow->getWidthFactor(),
			tabWindow->getHeightFactor(),
			tabWindow->STANDARD_HEIGHT,
			tabWindow->getWindowHeight());
	}// for

	viewChangingHeight = DEFAULT_VIEW_CHANGING_SIZE 
		* tabWindow->getHeightFactor();

	resources->resize((float)tabWindow->getMiddleX(), 
		(float)tabWindow->getTopLeftY(), 
		(float)tabWindow->getBottomRightX(),
		tabWindow->getWidthFactor(), 
		tabWindow->getHeightFactor(),
		bFullscreen);

	textXScale = tabWindow->getWidthFactor() 
		* textStandardXScale;
	textYScale = tabWindow->getHeightFactor() 
		* textStandardYScale;

}// resizeScales

void LowLevelTab::draw (unsigned int index, bool bFullScreen)
{
	if (!bFullScreen)
	{
		switch (state)
		{
		case UNSELECTED:
			drawUnselectedTab(index);
			break;
		case SELECTED:
			drawSelectedTab(index);
			drawTabWindowArea();
			break;
		case HOVER:
			drawHoveredTab(index);
			if (bSelected)
				drawTabWindowArea();
			break;
		}// switch
	}// if
	else
		drawFullScreen ();
}// void 

void LowLevelTab::drawSelectedTab (unsigned int index)
{ 
	// Starting positions of the tab
	float tabStartX;
	float tabStartY;

	// Draw orthographic information

	glHelper->setOrthographic();

	getTabStart (index, &tabStartX, &tabStartY);

	glHelper->drawFilledRectWH(tabStartX,
		tabStartY,
		width, height,
		selectedBoxColor);

	glHelper->drawText(textSelectedAlpha, 
		tabStartX + nameIndentX * tabWindow->getWidthFactor(), 
		tabStartY + (TAB_HEIGHT + nameIndentY) 
			* tabWindow->getHeightFactor(),
		0.0, tabScaleTextX, tabScaleTextY, 1.0f, 
		selectedTextColor, 0, name);

	glHelper->setOrthographicDone();
}// drawSelectedTab

void LowLevelTab::drawUnselectedTab (unsigned int index)
{
	// Starting positions of the tab
	float tabStartX;
	float tabStartY;

	glHelper->setOrthographic();

	getTabStart (index, &tabStartX, &tabStartY);

	glHelper->drawRectWH(tabStartX,
		tabStartY,
		width, height,
		unselectedBoxColor);

	glHelper->drawText(textUnselectedAlpha, 
		tabStartX + nameIndentX * tabWindow->getWidthFactor(), 
		tabStartY + (TAB_HEIGHT + nameIndentY) 
			* tabWindow->getHeightFactor(),
		0.0, tabScaleTextX, tabScaleTextY, 1.0f, 
		unselectedTextColor, 0, name);

	glHelper->setOrthographicDone();
}// drawUnselectedTab

void LowLevelTab::drawHoveredTab (unsigned int index)
{
	if (bSelected)
		drawSelectedTab(index);
	else
		drawUnselectedTab(index);

}// drawHoveredTab

void LowLevelTab::drawTabWindowArea ()
{
	time_t currTime;

	if (currentView.viewType == RESOURCES)
	{
		time(&currTime);
		if (currTime - resourceStartTime >= WAIT_TIME / 2)
		{
			resourceStartTime = currTime;
			resources->updateData();	
		}
	
		resources->draw(boinc_get_fraction_done());
	}
	else if (currentView.viewType == COMPLEX)
	{
		// Set the inner viewport to be the right half of the tab window
		setInnerViewport ();	

		drawComplex(0,1);

		// Set viewport to entire window
		setFullViewport ();

	}// else if
	else
	{
		// Set the inner viewport to be the right half of the tab window
		setInnerViewport ();

		drawCurrentModel();

		// Set viewport to entire window
		setFullViewport ();

	}// else

	// Draw window buttons
	drawButtons ();
	drawText ();
	handleButtons ();

}// drawTabWindowArea

void LowLevelTab::drawFullScreen ()
{
	time_t currTime;

	time(&currTime);
	if (currTime - resourceStartTime >= WAIT_TIME / 2)
	{
		resourceStartTime = currTime;
		resources->updateData();	
	}// if

	resources->draw(boinc_get_fraction_done(), true);

	setSSInnerViewport();

	models[0]->addUserRotation(1.25f);

	drawComplex(0,1);

	setFullViewport();

}// drawFullScreen

void LowLevelTab::handleMouseMove (int x, int y, int left, 
	int middle, int right)
{
	if (left)
    {        
		// Determine if movement is within the arcball window's
		// boundaries.
		if (currentView.bShowViewChangingControls && inModelDrawingWindow(x, y))
		{
			Point2fT MousePt;

			MousePt.s.X = (float)x - tabWindow->getMiddleX();
			MousePt.s.Y = (float)y - tabWindow->getTopLeftY();

			Quat4fT ThisQuat;

			// Update End Vector And Get Rotation As Quaternion
			models[currentModel]->getArcBall()->drag(
				&MousePt, &ThisQuat);						
			
			models[currentModel]->getArcBall()->
				addTransformation(&ThisQuat);
		}// if
    } // if

	handleButtonMouseInteraction(x, y, left!=0);

}// handleMouseMove

void LowLevelTab::handleMouseButton (int x, int y, int which, 
	int is_down)
{	
	bool bLeftClicked = false;

	if (is_down)
	{
		// Left mouse button
		if (which == 0)
		{		
			bLeftClicked = true;

			// Determine if movement is within the arcball window's
			// boundaries.
			if (currentView.bShowViewChangingControls && inModelDrawingWindow(x, y))
			{
				Point2fT mousePt;

				mousePt.s.X = 
					(float)x - tabWindow->getMiddleX();
				mousePt.s.Y = 
					(float)y - tabWindow->getTopLeftY();

				models[currentModel]->getArcBall()->currRotToLastRot();
				models[currentModel]->getArcBall()->click(&mousePt);
			}// if
		}// if
    }// if

	handleButtonMouseInteraction(x, y, bLeftClicked);

}// handleMouseButton

void LowLevelTab::handleKeyPress (int key1, int key2)
{
	if (currentView.bShowViewChangingControls)
	{
		// If single key is pressed or first of the two keys pressed
		switch (key1)
		{
		// Zoom Controls
		case 187:
			// += key
			// zoom in on object
			models[currentModel]->addToTranslateZ();
			break;
		case 189:
			// _- key
			// zoom in out object
			models[currentModel]->subtractFromTranslateZ();
			break;
#ifdef _WIN32
		case VK_LEFT:
			// Left arrow key
			// move object to the left
			models[currentModel]->subtractFromTranslateX();
			break;
		case VK_RIGHT:
			// Right arrow key
			// move object to the right
			models[currentModel]->addToTranslateX();
			break;
		case VK_UP:
			// Up arrow key
			// move object up
			models[currentModel]->addToTranslateY();
			break;
		case VK_DOWN:
			// Down arrow key
			// move object down
			models[currentModel]->subtractFromTranslateY();
			break;
#endif
		}// switch
	}// if

	if (currentView.viewType == MODELS)
	{
		switch (key1)
		{
		// Set Draw Representation For Models
		case '1':
			models[currentModel]->setDrawRep(VDW);
			break;
		case '2':
			models[currentModel]->setDrawRep(CPK);
			break;
		case '3':
			models[currentModel]->setDrawRep(LINE);
			break;
		}// switch
	}// if

	// If a ligand is currently shown, allow 
	// user to switch between minenergy and minrmsd
	if ((currentView.viewType == MODELS && currentModel == 1)
		|| currentView.viewType == COMPLEX)
	{
		switch (key1)
		{
		case 'm':
		case 'M':
			bMinEner = !bMinEner;
			changeLigandBasedOnBMinEner();
			break;
		}// switch
	}


}// handleKeyPress

void LowLevelTab::handleKeyRelease (int key1, int key2)
{
}// handleKeyRelease

// Change Ligand Based on bMinEner
void LowLevelTab::changeLigandBasedOnBMinEner ()
{
	if (bMinEner)
	{
		models[1]->setPDBFilename("screenenergy.pdb");
		models[1]->setPSFFilename("screenenergy.psf");
		models[1]->readFile();
	}
	else
	{
		models[1]->setPDBFilename("screenrmsd.pdb");
		models[1]->setPSFFilename("screenrmsd.psf");
		models[1]->readFile();
	}
}// changeLigandBasedOnBMinEner

// ------------------------------------------------------------
// Viewport Functions
// ------------------------------------------------------------

void LowLevelTab::setInnerViewport ()
{
	// Set Inner Viewport for the model
	glHelper->setViewport(tabWindow->getMiddleX(),
		tabWindow->getWindowHeight() 
			- tabWindow->getBottomRightY() 
			+ (int)viewChangingHeight + 2, 
		tabWindow->getBottomRightX(), 
		tabWindow->getWindowHeight() 
			- tabWindow->getTopLeftY() - 1);

}// setInnerViewport

void LowLevelTab::setSSInnerViewport ()
{
	// Set Inner Viewport for the model
	glHelper->setViewport((int)(135 * tabWindow->getWidthFactor()),
		0, 
		tabWindow->getWindowWidth(), 
		(int)(tabWindow->getWindowHeight() - 60 * tabWindow->getHeightFactor()));
}// setSSInnerViewport

void LowLevelTab::setFullViewport ()
{
	glHelper->setViewport(0, 0, (int)tabWindow->getWindowWidth(), 
		(int)tabWindow->getWindowHeight());
}// setFullViewport

// ------------------------------------------------------------
// Button Handling Functions
// ------------------------------------------------------------

void LowLevelTab::handleButtons ()
{
	for (unsigned int i = 0; i < viewChangingButtons.size(); i++)
	{
		// Must check both state and selected since to be "Selected"
		// the button must be able to hold a state while it is not
		// currently clicked
		if (viewChangingButtons[i]->isSelected() || 
			viewChangingButtons[i]->getState() == SELECTED)
		{
			performButtonAction(viewChangingButtons[i]->getActionID());
		}// if
	}// for 

}// handleButtons

void LowLevelTab::handleButtonMouseInteraction (int x, int y, 
	bool leftClicked)
{
	// Counter variables
	unsigned int i;
	
	// Index of the newly selected button. Used to unselect the 
	// other buttons (if any were currently selected)
	int newSelected = -1; 

	// Check the bioType buttons for mouse interaction
	for (i = 0; i < bioTypeButtons.size(); i++)
	{
		if (bioTypeButtons[i]->determineState(x,y, leftClicked))
		{
			newSelected = i;
			break;
		}// if
	}// for

	// Unselect other buttons if a new one is selected
	if (newSelected != -1)
	{
		performButtonAction(bioTypeButtons[newSelected]->getActionID());

		// On switch, make sure to re-parse the files
		models_startTime -= WAIT_TIME;
		resourceStartTime -= WAIT_TIME;

		for (i = 0; i < bioTypeButtons.size(); i++)
			if (i != newSelected)
				bioTypeButtons[i]->unselect();
	}// if

	if (currentView.bShowViewChangingControls)
	{
		// Check the view changing buttons for mouse interaction
		for (i = 0; i < viewChangingButtons.size(); i++)
		{
			if (viewChangingButtons[i]->determineState(x,y, leftClicked))
			{
				newSelected = i;
				break;
			}// if
		}// for

		// Unselect other buttons if a new one is selected
		if (newSelected != -1)
		{
			for (i = 0; i < viewChangingButtons.size(); i++)
				if (i != newSelected)
					viewChangingButtons[i]->unselect();
		}// if
	}// if
}// handleButtonMouseInteraction


void LowLevelTab::performButtonAction (int actionID)
{
	switch (actionID)
	{
	case ACT_ZOOM_IN:
		models[currentModel]->addToTranslateZ();
		break;
	case ACT_ZOOM_OUT:
		models[currentModel]->subtractFromTranslateZ();
		break;
	case ACT_ROTATE_LEFT:
		models[currentModel]->addUserRotation(5.0f);
		break;
	case ACT_ROTATE_RIGHT:
		models[currentModel]->subtractUserRotation(5.0f);
		break;
	case ACT_DISPLAY_PROTEIN:
		currentModel = 0;
		currentView.viewType = MODELS;
		currentView.bShowViewChangingControls = true;
		break;
	case ACT_DISPLAY_LIGAND:
		currentModel = 1;
		currentView.viewType = MODELS;
		currentView.bShowViewChangingControls = true;
		break;
	case ACT_DISPLAY_COMPLEX:
		// Use protein model as current so that all transformation
		// are applied to it.
		currentModel = 0;
		currentView.viewType = COMPLEX;
		currentView.bShowViewChangingControls = true;
		break;
	case ACT_DISPLAY_RESOURCES:
		currentView.viewType = RESOURCES;
		currentView.bShowViewChangingControls = false;
		break;
	}// switch

}// performButtonAction

// ------------------------------------------------------------
// Mouseclick Checking Functions
// ------------------------------------------------------------

// Name: inModelDrawingWindow
// Description: Determine if the x,y location is located within 
//	the boundaries of the viewport that draws the low level 
//	model.
// Parameters:
//	x, a x coordinate
//	y, a y coordinate
// Returns: true if it is the viewport, false otherwise

bool LowLevelTab::inModelDrawingWindow (int x, int y)
{
	if (x <= tabWindow->getBottomRightX() 
			&& x >= tabWindow->getMiddleX()
			&& y <= tabWindow->getBottomRightY()
				- (int)viewChangingHeight - 2
			&& y >= tabWindow->getTopLeftY())
		return true;
	
	return false;
}// inModelDrawingWindow

// ------------------------------------------------------------
// Button Drawing Functions
// ------------------------------------------------------------

void LowLevelTab::drawButtons ()
{
	unsigned int i;

	glHelper->setOrthographic();

	if (currentView.bShowViewChangingControls)
	{
		for (i = 0; i < viewChangingButtons.size(); i++)
			viewChangingButtons[i]->draw();
	}// if

	for (i = 0; i < bioTypeButtons.size(); i++)
		bioTypeButtons[i]->draw();

	glHelper->setOrthographicDone();
}// drawButtons

// ------------------------------------------------------------
// Text Drawing Functions
// ------------------------------------------------------------

void LowLevelTab::drawText ()
{
	int tempWidth;
	int max_ascent;
	int max_descent;
	int tempHeight;
	char textBuf[255];

	glHelper->setOrthographic();

	// If a ligand is currently being displayed, draw the text
	// describing whether it is the minener or minrmsd ligand
	if ((currentView.viewType == MODELS && currentModel == 1)
		|| currentView.viewType == COMPLEX)
	{
		if (bMinEner)
			strcpy(textBuf, "Min Energy");
		else
			strcpy(textBuf, "Min RMSD");

		glHelper->getDrawnTextProperties (textBuf, 0, &tempWidth, 
			&max_ascent, &max_descent);
		
		tempHeight = max_ascent + max_descent;

		glHelper->drawText(.1f, 
			tabWindow->getBottomRightX() - (tempWidth + ligandPaddingX) 
				* ligandTextScaleX,
			tabWindow->getTopLeftY() - (tempHeight + ligandPaddingY) 
				* ligandTextScaleY,
			0.0,
			ligandTextScaleX, ligandTextScaleY, 1.0f, 
			textColor, 0, textBuf);
	}// if

	glHelper->setOrthographicDone ();

}// drawText

// ------------------------------------------------------------
// Model Drawing Functions
// ------------------------------------------------------------

void LowLevelTab::drawCurrentModel ()
{
	time_t currTime;

	// Set acrball window boundaries
	models[currentModel]->getArcBall()->setBounds(
		(float)(tabWindow->getBottomRightX() 
			- tabWindow->getMiddleX()),
		(float)(tabWindow->getBottomRightY() 
			- tabWindow->getTopLeftY()));
		            
	time(&currTime);
	if (currTime - models_startTime >= WAIT_TIME)
	{
		models_startTime = currTime;
		models[currentModel]->readFile();
	}// if

	// Set the inner viewport to be the right half of the tab window
	setInnerViewport ();

	models[currentModel]->draw();

	// Set viewport to entire window
	setFullViewport ();

}// drawCurrentModel

void LowLevelTab::drawComplex(unsigned int index1, unsigned int index2){
	time_t currTime;

	// Set acrball window boundaries
	models[index1]->getArcBall()->setBounds((float)(tabWindow->getBottomRightX() - tabWindow->getMiddleX()),
		(float)(tabWindow->getBottomRightY() - tabWindow->getTopLeftY()));
		            
	time(&currTime);
	if (currTime - models_startTime >= WAIT_TIME){
		models_startTime = currTime;
		models[index1]->readFile();
		models[index2]->readFile();
	}

	if (models[index1]->getNumAtoms() > 0 || models[index2]->getNumAtoms() > 0){
		/*Kevin Kreiser 16.6.9
		The following is a hack by that I did to remedy steric clashes between the ligand and protein
		due to centroids being calculated for both molecules separatly even though they are being displayed
		as a complex. I fixed it by calculating a new centroid based on complex*/

		//find the weight that the ligands centroid should hold
		float weight=(float)models[index2]->GetAtoms()/(float)models[index1]->GetAtoms();
		//calculate the center of the complex by adding the centroid of the protien plus the weighted ligand centroid
		float center[3],tempCenter[3];
		models[index1]->GetCentroid(center);	models[index2]->GetCentroid(tempCenter);
		center[0]+=tempCenter[0]*weight;	center[1]+=tempCenter[1]*weight;	center[2]+=tempCenter[2]*weight;

		//get the protein's old centroid
		models[index1]->GetCentroid(tempCenter);
		//set the new one
		models[index1]->SetCentroid(center);
		//draw the protein
		models[index1]->drawMultiple(true);
		//give it the old center back
		models[index1]->SetCentroid(tempCenter);

		//get the ligand's old centroid
		models[index2]->GetCentroid(tempCenter);
		//set the new one
		models[index2]->SetCentroid(center);
		//draw the ligand
		models[index2]->drawMultiple(false);
		//give it the old center back
		models[index2]->SetCentroid(tempCenter);
	}
	
	/*
	else
		models[index1]->drawNoAtomsText(
			(float)glHelper->getViewportWidth(), 
			(float)glHelper->getViewportHeight());
	*/

}
